package com.treasure.mall.biz.service.core.live.impl;

import com.treasure.mall.biz.base.AbstractSearchableCrudService;
import com.treasure.mall.biz.base.SpecificationAndSort;
import com.treasure.mall.biz.dto.BaseSaveDTO;
import com.treasure.mall.biz.dto.BaseSearchDTO;
import com.treasure.mall.biz.dto.condition.LiveRoomSearchCondition;
import com.treasure.mall.biz.dto.live.ApplyLiveDTO;
import com.treasure.mall.biz.dto.live.DirectorSaveDTO;
import com.treasure.mall.biz.dto.live.LiveRecommendSaveDTO;
import com.treasure.mall.biz.dto.live.LiveRoomFanSaveDTO;
import com.treasure.mall.biz.entity.embeddable.LiveRoomData_;
import com.treasure.mall.biz.entity.embeddable.MerchantData_;
import com.treasure.mall.biz.entity.live.LiveDirectorPO;
import com.treasure.mall.biz.entity.live.LiveRoomNoticeRecordsPO;
import com.treasure.mall.biz.entity.live.LiveRoomPO;
import com.treasure.mall.biz.entity.live.LiveRoomPO_;
import com.treasure.mall.biz.entity.user.MerchantPO;
import com.treasure.mall.biz.entity.user.MerchantPO_;
import com.treasure.mall.biz.entity.user.UserPO;
import com.treasure.mall.biz.entity.user.UserPO_;
import com.treasure.mall.biz.mapstruct.LiveRoomMapStruct;
import com.treasure.mall.biz.repository.live.LiveRoomNoticeRecordsRepository;
import com.treasure.mall.biz.repository.live.LiveRoomRepository;
import com.treasure.mall.biz.service.core.live.LiveDirectorService;
import com.treasure.mall.biz.service.core.live.LiveRoomFanService;
import com.treasure.mall.biz.service.core.live.LiveRoomService;
import com.treasure.mall.biz.service.core.user.MerchantService;
import com.treasure.mall.biz.service.core.user.UserService;
import com.treasure.mall.zbq.common.base.ApiResult;
import com.treasure.mall.zbq.common.base.ResultCodeEnum;
import com.treasure.mall.zbq.common.exception.ApiException;
import com.treasure.mall.zbq.common.ienum.base.CodeDescEnumHelper;
import com.treasure.mall.zbq.common.ienum.live.LiveEnums;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 
 * 直播间接口实现
 * +---------------------------------------------------------
 * * @package: com.treasure.mall.biz.service.core.live.impl
 * * @author: guomw (guomwchen@foxmail.com)
 * * @date: 2020/6/11 20:16
 * * @since: V1.0.0
 * +---------------------------------------------------------
 * 注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的
 * Copyright 2019-2022 com.treasure.mall.biz.service.core.live.impl Inc. All rights reserved.
 */
@Service
public class LiveRoomServiceImpl extends AbstractSearchableCrudService<LiveRoomPO, Long> implements LiveRoomService {

    private LiveRoomRepository liveRoomRepository;
    @Resource
    private MerchantService merchantService;
    @Resource
    private LiveDirectorService directorService;
    @Resource
    private UserService userService;
    @Resource
    private LiveRoomFanService liveRoomFanService;
    @Autowired
    private LiveRoomNoticeRecordsRepository liveRoomNoticeRecordsRepository;


    protected LiveRoomServiceImpl(LiveRoomRepository repository) {
        super(repository);
        this.liveRoomRepository = repository;
    }

    @Override
    protected SpecificationAndSort<LiveRoomPO> specificationAndSort(BaseSearchDTO searchDTO) {
        LiveRoomSearchCondition condition = (LiveRoomSearchCondition) searchDTO;

        Specification<LiveRoomPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (condition.getEnabled() != null) {
                predicates.add(cb.equal(root.get(LiveRoomPO_.enabled), condition.getEnabled()));
            }
            if (condition.getMerchantId() > 0) {
                predicates.add(cb.equal(root.get(LiveRoomPO_.merchant).get(MerchantPO_.merchantId), condition.getMerchantId()));
            }
            if (!StringUtils.isEmpty(condition.getMerchantKey())) {
                predicates.add(cb.or(
                        cb.like(root.get(LiveRoomPO_.merchant).get(MerchantPO_.user).get(UserPO_.realName), likeAll(condition.getMerchantKey())),
                        cb.like(root.get(LiveRoomPO_.merchant).get(MerchantPO_.user).get(UserPO_.mobile), likeAll(condition.getMerchantKey()))
                ));
            }
            if (!StringUtils.isEmpty(condition.getShopName())) {
                predicates.add(cb.like(root.get(LiveRoomPO_.merchant).get(MerchantPO_.data).get(MerchantData_.title), likeAll(condition.getShopName())));
            }
            if (!StringUtils.isEmpty(condition.getTitle())) {
                predicates.add(cb.like(root.get(LiveRoomPO_.data).get(LiveRoomData_.title), likeAll(condition.getTitle())));
            }
            if (condition.getAuditStatus() != -1) {
                LiveEnums.AuditStatus auditStatus = CodeDescEnumHelper.getEnumTypeByCode(LiveEnums.AuditStatus.class, condition.getAuditStatus());
                predicates.add(cb.equal(root.get(LiveRoomPO_.auditStatus), auditStatus));
            }

            if (condition.getPlatform() != null) {
                predicates.add(cb.equal(root.get(LiveRoomPO_.platform), condition.getPlatform()));
            }
            // 只有私域才能推荐
            if (condition.getRecommendFlag() != null) {
                predicates.add(cb.equal(root.get(LiveRoomPO_.recommendFlag), condition.getRecommendFlag()));
                predicates.add(cb.equal(root.get(LiveRoomPO_.platform), false));
            }

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "livePlaying", "orderWeight");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    @Transactional
    public LiveRoomPO apply(ApplyLiveDTO applyLiveDTO) {
        return save(applyLiveDTO);
    }

    @Override
    public LiveRoomPO findByMerchant(Long merchantId) {
        return liveRoomRepository.findTopByMerchant_MerchantId(merchantId);
    }

    @Override
    @Transactional
    public LiveRoomPO edit(Long roomId, ApplyLiveDTO applyLiveDTO) {
        LiveRoomPO liveRoomPO = findById(roomId);
        liveRoomPO.getData().setTitle(applyLiveDTO.getTitle());
        liveRoomPO.getData().setDescription(applyLiveDTO.getDescription());
        liveRoomPO.getData().setLiveAddr(applyLiveDTO.getLiveAddr());
        liveRoomPO.getData().setLogo(applyLiveDTO.getLogo());
        liveRoomPO.getData().setLandscapeCover(applyLiveDTO.getLandscapeCover());
        liveRoomPO.getData().setPortraitCover(applyLiveDTO.getPortraitCover());

        return save(liveRoomPO);
    }

    @Override
    @Transactional
    public void sort(Long roomId, int orderWeight) {
        LiveRoomPO liveRoomPO = findById(roomId);
        liveRoomPO.setOrderWeight(orderWeight);

        save(liveRoomPO);
    }

    /**
     * 审核直播间
     *
     * @param id
     * @param auditStatus
     * @param reason
     * @return
     */
    @Override
    @Transactional
    public void audit(Long id, LiveEnums.AuditStatus auditStatus, String reason) {
        LiveRoomPO po = findById(id);
        po.setReason(reason);
        po.setAuditStatus(auditStatus);
        if (auditStatus == LiveEnums.AuditStatus.SUCCESS) {
            po.setOpenTime(LocalDateTime.now());
            po.setEnabled(false);
            //同时增加一个主播
            DirectorSaveDTO directorSaveDTO = new DirectorSaveDTO(po.getMerchant().getUser().getUserId(), id, po.getMerchant().getUser().getNickName());
            directorSaveDTO.setOwner(true);
            directorService.save(directorSaveDTO);
        }
        repository.save(po);
    }

    @Override
    @Transactional
    public void addDirector(Long roomId, Long userId) {
        LiveDirectorPO liveDirectorPO = directorService.findByRoomAndUser(roomId, userId);
        if (liveDirectorPO != null) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "该用户已经是这个直播间的主播"));
        }
        DirectorSaveDTO directorSaveDTO = new DirectorSaveDTO(userId, roomId, liveDirectorPO.getDirectorName());
        directorService.save(directorSaveDTO);
    }

    @Override
    @Transactional
    public void follow(Long roomId, Long userId) {
        UserPO userPO = userService.findById(userId);
        liveRoomFanService.save(new LiveRoomFanSaveDTO(roomId, userPO));
    }

    @Override
    @Transactional
    public void unfollow(Long roomId, Long userId) {
        liveRoomFanService.delete(roomId, userId);
    }

    @Override
    public void enableToggle(Long roomId, boolean enabled) {
        LiveRoomPO liveRoomPO = findById(roomId);
        if (!enabled && liveRoomPO.isPlaying()) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "当前直播间正在直播，暂时无法冻结"));
        }
        liveRoomPO.setEnabled(enabled);

        save(liveRoomPO);
    }

    @Override
    @Transactional
    public void setRewardRate(Long roomId, BigDecimal rate) {
        LiveRoomPO liveRoomPO = findById(roomId);
        liveRoomPO.setRewardRate(rate);

        save(liveRoomPO);
    }

    @Override
    @Transactional
    public void setRewardRate(Long roomId, BigDecimal rate, BigDecimal rebateRateOne, BigDecimal rebateRateTwo) {
        LiveRoomPO liveRoomPO = findById(roomId);
        liveRoomPO.setRewardRate(rate);
        liveRoomPO.setRebateRateOne(rebateRateOne);
        liveRoomPO.setRebateRateTwo(rebateRateTwo);
        save(liveRoomPO);
    }


    @Override
    public LiveRoomPO save(BaseSaveDTO saveDTO) {
        ApplyLiveDTO applyLiveDTO = (ApplyLiveDTO) saveDTO;

        MerchantPO merchantPO = merchantService.findById(applyLiveDTO.getMerchantId());
        if (merchantPO == null) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.NOT_AUTHORITY));
        }
        LiveRoomPO liveRoomPO = this.findByMerchant(merchantPO.getMerchantId());
        if (liveRoomPO == null) {
            liveRoomPO = new LiveRoomPO();
            liveRoomPO.setMerchant(merchantPO);
        }
        liveRoomPO.setData(LiveRoomMapStruct.INSTANCE.dto2LiveRoomData(applyLiveDTO));
        liveRoomPO.setAuditStatus(LiveEnums.AuditStatus.WAIT);
        liveRoomPO.setPlatform(false);
        liveRoomPO = repository.save(liveRoomPO);

        return liveRoomPO;
    }

    @Override
    public boolean modifyPlatformType(Long id, boolean platform) {
        liveRoomRepository.modifyPlatform(id, platform);
        return true;
    }


    @Override
    public boolean modifyRecommend(LiveRecommendSaveDTO dto) {
        LiveRoomPO liveRoomPO = findById(dto.getRoomId());
        if (liveRoomPO != null) {
            liveRoomPO.setRecommendFlag(dto.isRecommend());
            liveRoomPO.setBackgroundImage(dto.getBackgroundImage());
            liveRoomPO.setBackgroundColor(dto.getBackgroundColor());
            repository.save(liveRoomPO);
            return true;
        }
        return false;
    }


    /**
     * 检查用户是否是主播
     *
     * @param roomId
     * @param userId
     * @return
     */
    @Override
    public boolean checkDirectorUser(Long roomId, Long userId) {
        LiveDirectorPO liveDirectorPO = directorService.findByRoomAndUser(roomId, userId);

        return liveDirectorPO != null;
    }

    /**
     * 获取用户授权的直播间列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<LiveRoomPO> getUserAuthRoomList(Long userId) {
        List<Long> roomIds = directorService.findRoomIdsByUserId(userId);
        List<LiveRoomPO> roomPOS = liveRoomRepository.findByIdInAndAuditStatusAndEnabledIsTrue(roomIds, LiveEnums.AuditStatus.SUCCESS);
        if (roomPOS == null || roomPOS.size() == 0) {
            return null;
        }
        //获取未开播的直播间
        return roomPOS.stream().filter(item -> StringUtils.isEmpty(item.getSessionId())).collect(Collectors.toList());
    }


    @Override
    public void modifyLivePlaying(Long roomId, boolean livePlaying) {
        liveRoomRepository.modifyLivePlaying(roomId, livePlaying ? 1 : 0);
    }

    /**
     * 设置直播间公告内容
     *
     * @param roomId
     * @param notice
     */
    @Override
    public void setNoticeContent(Long roomId, String notice) {
        liveRoomRepository.setNoticeContent(roomId, notice);

        /**
         * 添加公告记录
         */
        LiveRoomNoticeRecordsPO noticeRecordsPO = new LiveRoomNoticeRecordsPO();
        noticeRecordsPO.setNotice(notice);
        noticeRecordsPO.setRoomId(roomId);
        liveRoomNoticeRecordsRepository.save(noticeRecordsPO);

    }

    /**
     * 启用或禁用公告
     *
     * @param roomId
     * @param enable
     */
    @Override
    public void enableNotice(Long roomId, boolean enable) {
        liveRoomRepository.enableNotice(roomId, enable);
    }
}
